package com.hzw.saas.service.hpc.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzw.saas.api.hpc.IHpcAccountProviderService;
import com.hzw.saas.api.hpc.IHpcAccountService;
import com.hzw.saas.api.hpc.bo.HpcAccountBo;
import com.hzw.saas.api.hpc.bo.HpcAccountIdProviderBo;
import com.hzw.saas.api.hpc.bo.HpcAccountProviderBo;
import com.hzw.saas.api.hpc.enums.HpcProviderType;
import com.hzw.saas.api.property.IPropertyService;
import com.hzw.saas.api.property.enmus.SysDictKeyEnum;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.config.util.PageParam;
import com.hzw.saas.common.config.util.PageUtils;
import com.hzw.saas.common.util.IdWorker;
import com.hzw.saas.common.util.Json;
import com.hzw.saas.service.hpc.mapper.HpcAccountProviderMapper;
import com.hzw.saas.service.hpc.model.HpcAccountProvider;
import lombok.RequiredArgsConstructor;
import ma.glasnost.orika.MapperFacade;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户超算中心帐号表 服务实现类
 * </p>
 *
 * @author sonam
 * @since 2021-03-22
 */
@RequiredArgsConstructor
@Service("hpcAccountProviderServiceImpl")
public class HpcAccountProviderServiceImpl extends ServiceImpl<HpcAccountProviderMapper, HpcAccountProvider> implements IHpcAccountProviderService, IService<HpcAccountProvider> {

    private final MapperFacade mapperFacade;
    private final IdWorker idWorker;

    @Resource(name = "hpcAccountServiceImpl")
    private IHpcAccountService hpcAccountService;

    @Resource(name = IPropertyService.SYS_DICT_BEAN)
    private IPropertyService<SysDictKeyEnum> propertyService;

    @Override
    public List<HpcAccountProviderBo> getList() {
        return mapperFacade.mapAsList(this.list(), HpcAccountProviderBo.class);
    }

    @Override
    public void update(HpcAccountProviderBo hpcAccountProviderBo) {
        this.updateById(mapperFacade.map(hpcAccountProviderBo, HpcAccountProvider.class));
    }

    @Override
    public HpcAccountProviderBo getById(String providerId) {
        return mapperFacade.map(super.getById(providerId), HpcAccountProviderBo.class);
    }

    @Override
    public Optional<HpcAccountProviderBo> getByHpcAccountId(String hpcAccountId, HpcProviderType hpcProviderType) {
        HpcAccountProvider result = this.baseMapper.getByHpcAccountId(hpcAccountId, hpcProviderType.value());
        return Optional.ofNullable(mapperFacade.map(result, HpcAccountProviderBo.class));
    }

    @Override
    public List<HpcAccountIdProviderBo> getByHpcAccountIds(Collection<String> hpcAccountIds, HpcProviderType hpcProviderType) {
        if (CollectionUtils.isEmpty(hpcAccountIds)){
            return Collections.emptyList();
        }else {
            return this.baseMapper.getByHpcAccountIds(hpcAccountIds, hpcProviderType.value());
        }
    }

    @Override
    public List<HpcAccountProviderBo> list(HpcAccountProviderBo hpcAccountProviderBo) {
        HpcAccountProvider hpcAccountProvider = mapperFacade.map(hpcAccountProviderBo, HpcAccountProvider.class);
        List<HpcAccountProvider> hpcAccountPools = this.list(Wrappers.<HpcAccountProvider>query().setEntity(hpcAccountProvider));
        return mapperFacade.mapAsList(hpcAccountPools, HpcAccountProviderBo.class);
    }

    @Override
    public IPage<HpcAccountProviderBo> listByPage(PageParam pageParam, HpcAccountProviderBo hpcAccountProviderBo) {
        HpcAccountProvider hpcAccountProvider = mapperFacade.map(hpcAccountProviderBo, HpcAccountProvider.class);
        List<HpcAccountProviderBo> providerCodes = getProviderCodes();

        IPage<HpcAccountProviderBo> pageData = PageUtils.convert(this.page(pageParam.convert(), Wrappers.<HpcAccountProvider>query().setEntity(hpcAccountProvider)), HpcAccountProviderBo.class);
        pageData.getRecords().forEach(record -> {
            for (HpcAccountProviderBo codes : providerCodes) {
                if (Objects.equals(codes.getProviderCode(), record.getProviderCode())) {
                    record.setProviderCodeName(codes.getProviderCodeName());
                }
            }
        });
        return pageData;
    }

    @Override
    public IPage<HpcAccountProviderBo> listByPage(PageParam pageParam, HpcProviderType providerType, String fuzzy) {
        if(StrUtil.isBlank(fuzzy)) {
            HpcAccountProviderBo hpcAccountProviderBo = new HpcAccountProviderBo();
            if(Objects.isNull(providerType)) {
                hpcAccountProviderBo.setProviderCode(HpcProviderType.BX.value());
            } else {
                hpcAccountProviderBo.setProviderCode(providerType.value());
            }
            return listByPage(pageParam, hpcAccountProviderBo);
        }
        return PageUtils.convert(this.lambdaQuery()
            .likeRight(HpcAccountProvider::getProviderName, fuzzy)
            .likeRight(HpcAccountProvider::getAdminUserName, fuzzy)
            .eq(providerType != null, HpcAccountProvider::getProviderCode, providerType.value())
            .page(pageParam.convert()), HpcAccountProviderBo.class);
    }

    private List<HpcAccountProviderBo> getProviderCodes() {
        String propertyValue = propertyService.getPropertyValue(SysDictKeyEnum.PROVIDER_TYPE);
        return Json.parseArray(propertyValue, HpcAccountProviderBo[].class);
    }

    @Override
    public void addBatch(List<HpcAccountProviderBo> hpcAccountProviderBos) {
        List<HpcAccountProviderBo> providerCodes = getProviderCodes();

        hpcAccountProviderBos.forEach(providerBo -> {
            String code = providerBo.getProviderCode();
            boolean flag = true;
            for (HpcAccountProviderBo providerCode : providerCodes) {
                if (Objects.equals(providerCode.getProviderCode(), code)) {
                    flag = false;
                    break;
                }
            }
            AssertUtil.assertThrow(StrUtil.format("不存在的供应商:{}", code), flag);

            if (providerBo.getCreateDate() == null) {
                providerBo.setCreateDate(new Date());
            }
            if (providerBo.getProviderId() == null) {
                providerBo.setProviderId(String.valueOf(idWorker.nextId()));
            }
        });
        this.saveBatch(mapperFacade.mapAsList(hpcAccountProviderBos, HpcAccountProvider.class));
    }

    @Override
    @Transactional
    public void deleteProvider(String providerId) {
        List<HpcAccountBo> hpcAccountPoolBos = hpcAccountService.query(new HpcAccountBo().setProviderId(providerId));
        AssertUtil.assertThrow("操作失败,请先删除当前供应商下的HPC账户", CollectionUtil.isNotEmpty(hpcAccountPoolBos));
        this.removeById(providerId);
    }

    @Override
    public List<String> getProviderIds(HpcProviderType hpcProviderType) {
        if(Objects.isNull(hpcProviderType)) {
            return Collections.emptyList();
        }
        List<HpcAccountProvider> providers = this.lambdaQuery().select(HpcAccountProvider::getProviderId).eq(HpcAccountProvider::getProviderCode, hpcProviderType.value()).list();
        return providers.stream().map(HpcAccountProvider::getProviderId).collect(Collectors.toList());
    }
}
